﻿using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using Automator.Classes;
using Automator.Runtime;
using Automator.Runtime.Classes;
using Automator.Tasks.Core;
using Automator.Windows;
using AvalonDock;

namespace Automator
{
    public partial class MainWindow : Window
    {
        private Solution solution;
        private bool _isDragging = false;
        private Point _startPoint;
        private bool _isContextMenuOpened = false;
        
        public MainWindow()
        {
            InitializeComponent();
        }
        
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            RegisterCustomRoutedCommands();
            
            string xmlPath = Path.Combine(Automator.Runtime.Environment.xmlDir,"settings.xml");
            if (File.Exists(xmlPath))
            {
                using (StreamReader sr = new StreamReader(xmlPath))
                {
                    if (!sr.EndOfStream)
                        Automator.Runtime.Settings.ReadSettings(sr.ReadToEnd());
                }
            }

            cmbOutputTargets.ItemsSource = new ObservableCollection<string>() { "Workflow", "Solution" };
            cmbOutputTargets.SelectedIndex = 0;

            lstClipboard.ItemsSource = TaskClipboard.Instance;
            solution = new Solution();
            
            ObservableCollection<RuntimeEntity> solutionWrapper = new ObservableCollection<RuntimeEntity>();
            solutionWrapper.Add(solution);
            solutionContent.SolutionInstance = solution;
            solutionContent.WorkflowTree = solutionTree;            
            solutionContent.WorkflowTree.ItemsSource = solutionWrapper;
            
            AddStartPageDocument();
        }
        
        private void MnuExit_Click(object sender, RoutedEventArgs e)
        {
            Close();
        }
        
        private void LstWorkflows_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;
            TreeView lstWorkflows = (sender as TreeView);
            if (lstWorkflows.SelectedItem != null)
            {
                if (lstWorkflows.SelectedItem is Workflow)
                    AddWorkflowDocument(lstWorkflows.SelectedItem as Workflow);
            }
        }

        private void ChkActive_Click(object sender, RoutedEventArgs e)
        {
            if (dockingManager.ActiveDocument is WorkflowDocument)
                (dockingManager.ActiveDocument as WorkflowDocument).WorkflowInstance.Modified = true;
            e.Handled = true;
        }

        private void WebAvalonDock_Click(object sender, RoutedEventArgs e)
        {
            Process.Start(new ProcessStartInfo("http://avalondock.codeplex.com"));
            e.Handled = true;
        }

        private void WebWPFToolkit_Click(object sender, RoutedEventArgs e)
        {
            Process.Start(new ProcessStartInfo("http://wpftoolkit.codeplex.com"));
            e.Handled = true;
        }
        
        private void WebAvalonEdit_Click(object sender, RoutedEventArgs e)
        {
            Process.Start(new ProcessStartInfo("http://avalonedit.net"));
            e.Handled = true;
        }
        
        private void WebAvalonWizard_Click(object sender, RoutedEventArgs e)
        {
            Process.Start(new ProcessStartInfo("http://avalonwizard.codeplex.com"));
            e.Handled = true;
        }

        private bool SaveChanges()
        {
            SaveChangesWindow window = new SaveChangesWindow();
            window.Owner = this;
            foreach (Workflow workflow in solution.Workflows)
                if (workflow.Modified || String.IsNullOrEmpty(workflow.FileName))
                    window.AddChangedDocument(workflow.Name);
            if (solution.Modified || (String.IsNullOrEmpty(solution.FileName) && solution.Workflows.Count > 0))
                window.AddChangedDocument(solution.Name);

            if (window.ChangedCount > 0)
            {
                if (window.ShowDialog().Value)
                {
                    switch (window.Result)
                    {
                        case WindowShowResult.Yes:
                            AutomatorCommands.SaveAll.Execute(null, null);
                            return true;
                        case WindowShowResult.No:
                            return true;
                        case WindowShowResult.Cancel:
                            return false;
                        default:
                            return false;
                    }
                }
                else
                    return false;
            }
            else
                return true;
        }

        private void Window_Closing(object sender, CancelEventArgs e)
        {
            e.Cancel = !SaveChanges();
            
            //saving layout
            if (!e.Cancel)
            {
                ObservableCollection<DocumentContent> docsToClose = new ObservableCollection<DocumentContent>();
                foreach (DocumentContent doc in dockingManager.Documents)
                    if (!doc.Name.Equals("outputContent") &&
                        !doc.Name.Equals("clipboardContent") &&
                        !doc.Name.Equals("solutionContent"))
                        docsToClose.Add(doc);
                foreach (DocumentContent doc in docsToClose)
                    doc.Close();
                string dockPath = Path.Combine(Automator.Runtime.Environment.xmlDir, "layout.xml");
                dockingManager.SaveLayout(dockPath);
            }
        }
        
        private void LstOutput_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            if (lstOutput.SelectedItem != null)
            {
                LogVisualizer window = new LogVisualizer();
                window.Owner = this;
                window.pnlContent.DataContext = lstOutput.SelectedItem as LogItem;
                window.Show();
            }
        }

        private void treeWorkflow_MouseMove(object sender, MouseEventArgs e)
        {
            if(!_isDragging && !_isContextMenuOpened && e.LeftButton == MouseButtonState.Pressed)
            {
                e.Handled = true;
                if ((e.OriginalSource as FrameworkElement).DataContext != null)
                {
                    Point position = e.GetPosition(null);
                    if (Math.Abs(position.X - _startPoint.X) > SystemParameters.MinimumHorizontalDragDistance ||
                        Math.Abs(position.Y - _startPoint.Y) > SystemParameters.MinimumVerticalDragDistance)
                    {
                        StartDrag(e);
                    }
                }
            }
        }
        
        private void treeWorkflow_DragOver(object sender, DragEventArgs e)
        {
            if(e.Data.GetDataPresent(DataFormats.Serializable.ToString()))
            {
                e.Effects = DragDropEffects.Move;
            }
            else
            {
                e.Effects = DragDropEffects.None;
            }
            e.Handled = true;
        }
        
        private void treeWorkflow_Drop(object sender, DragEventArgs e)
        {
            if(e.Data.GetDataPresent(DataFormats.Serializable.ToString()))
            {
                e.Handled = true;
                Task sourceTask = (Task)e.Data.GetData(DataFormats.Serializable.ToString());
                Task targetTask = (e.OriginalSource as FrameworkElement).DataContext as Task;
                if (!sourceTask.Equals(targetTask))
                {
                    // removing source
                    if (sourceTask.ParentTask != null)
                        sourceTask.ParentTask.RemoveDependency(sourceTask);
                    else
                        (dockingManager.ActiveDocument as WorkflowDocument).WorkflowInstance.Tasks.Remove(sourceTask);
                    
                    // add it to target
                    if (targetTask != null)
                        targetTask.AddDependency(sourceTask);
                    else
                        (dockingManager.ActiveDocument as WorkflowDocument).WorkflowInstance.Tasks.Add(sourceTask);
                    
                    (dockingManager.ActiveDocument as WorkflowDocument).WorkflowInstance.Modified = true;
                }
            }
        }
        
        private void treeWorkflow_MouseDown(object sender, MouseButtonEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
                _startPoint = e.GetPosition(null);
        }
        
        private void StartDrag(MouseEventArgs e)
        {
            _isDragging = true;
            Task task = (e.OriginalSource as FrameworkElement).DataContext as Task;
            DataObject data = new DataObject(DataFormats.Serializable.ToString(), task);
            DragDropEffects de = DragDrop.DoDragDrop(e.Source as FrameworkElement, data, DragDropEffects.Move);
            _isDragging = false;
        }
        
        private void ContextMenu_Opened(object sender, RoutedEventArgs e)
        {
            _isContextMenuOpened = true;
        }

        private void ContextMenu_Closed(object sender, RoutedEventArgs e)
        {
            _isContextMenuOpened = false;
        }
                
        private void ToolBar_Loaded(object sender, RoutedEventArgs e)
        {
            ToolBar toolBar = sender as ToolBar;
            toolBar.Background = new SolidColorBrush(Colors.Transparent);
            toolBar.Focusable = false;

            foreach (FrameworkElement a in toolBar.Items)
            {
                ToolBar.SetOverflowMode(a, OverflowMode.Never);
            }
            FrameworkElement overflowGrid = toolBar.Template.FindName("OverflowGrid", toolBar) as FrameworkElement;
            if (overflowGrid != null)
            {
                overflowGrid.Visibility = Visibility.Collapsed;
            }
        }

        private void LstClipboard_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            if (dockingManager.ActiveDocument is WorkflowDocument && lstClipboard.SelectedItem != null)
            {
                TaskClipboard.Paste(lstClipboard.SelectedItem as Task,
                                    (dockingManager.ActiveDocument as WorkflowDocument).WorkflowInstance);
            }
        }

        private void treeWorkflow_RightClick(object sender, MouseEventArgs e)
        {
            if (sender != null && sender is TreeViewItem)
                (sender as TreeViewItem).Focus();
        }

        private void cmbOutputTargets_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            DockingManager_ActiveDocumentChanged(null, new EventArgs());
        }
        
        private void DockingManager_Loaded(object sender, RoutedEventArgs e)
        {
            string dockPath = Path.Combine(Automator.Runtime.Environment.xmlDir, "layout.xml");
            if (File.Exists(dockPath))
            {
                dockingManager.RestoreLayout(dockPath);
                AddStartPageDocument();
            }
            else
                outputContent.ToggleAutoHide();
        }        
    }
}
